/*
 * WCH_LINLK port debug driver for WCH RISC-V mcu :
   CH32V103X;CH32V20X,CH32V30X;CH56X;CH57X;CH58X
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <jtag/adapter.h>
#include <jtag/interface.h>
#include <jtag/commands.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include "cmsis_dap.h"
#ifdef _WIN32
#include <windows.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include "hidapi.h"
typedef int(__stdcall *pCH375OpenDevice)(unsigned long iIndex);
typedef void(__stdcall *pCH375CloseDevice)(unsigned long iIndex);
typedef unsigned long(__stdcall *pCH375SetTimeout)(unsigned long iIndex,
												   unsigned long iWriteTimeout,
												   unsigned long iReadTimeout);
typedef unsigned long(__stdcall *pCH375ReadEndP)(unsigned long iIndex,
												 unsigned long iPipeNum,
												 void *iBuffer,
												 unsigned long *ioLength);
typedef unsigned long(__stdcall *pCH375WriteEndP)(unsigned long iIndex,
												  unsigned long iPipeNum,
												  void *iBuffer,
												  unsigned long *ioLength);
HMODULE hModule = 0;
BOOL gOpen = FALSE;
ULONG gIndex = 0;
pCH375OpenDevice pOpenDev;
pCH375CloseDevice pCloseDev;
pCH375SetTimeout pSetTimeout;
pCH375ReadEndP pReadData;
pCH375WriteEndP pWriteData;
#else
#include "libusb_helper.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdint.h>
int gIndex = 0;
static const uint16_t wlink_vids[] = {0x1a86, 0};
static const uint16_t wlink_pids[] = {0x8010, 0};
struct jtag_libusb_device_handle *wfd = NULL;
int pWriteData(int dev, int endpoint, unsigned char *buf, unsigned long *length)
{
	int ret,pr;
	length = (int *)length;
	ret =jtag_libusb_bulk_write(wfd, endpoint, buf, *length, 3000,&pr);
	if(ret==ERROR_OK)
		 return 1;
	else
		 return ret;
}
int pReadData(int dev, int endpoint, unsigned char *buf, unsigned long *length)
{
	int ret,pr;
	length = (int *)length;
	if (endpoint == 1)
	{
		ret=jtag_libusb_bulk_read(wfd, 0x81, buf, *length, 3000,&pr);
	}
	else
	{
		ret=jtag_libusb_bulk_read(wfd, 0x82, buf, *length, 3000,&pr);
	}
	if(ret==ERROR_OK)
		 return 1;
	else
		 return ret;
}
#endif
bool pageerase=false;
unsigned char riscvchip;
unsigned  int  chip_type;
unsigned long chipiaddr;
unsigned long pagesize;
unsigned long ramaddr;
bool wchwlink;
int noloadflag=0; 
uint8_t flash_op103[ ] ={
    0x93, 0x77, 0x15, 0x00, 0x41, 0x11, 0x99, 0xCF, 0xB7, 0x06, 0x67, 0x45, 0xB7, 0x27, 0x02, 0x40, 
    0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xEF, 0xCD, 0xD4, 0xC3, 0x13, 0x07, 0xB7, 0x9A, 0xD8, 0xC3, 
    0xD4, 0xD3, 0xD8, 0xD3, 0x93, 0x77, 0x25, 0x00, 0x9D, 0xC7, 0xB7, 0x27, 0x02, 0x40, 0x98, 0x4B, 
    0xAD, 0x66, 0x37, 0x38, 0x00, 0x40, 0x13, 0x67, 0x47, 0x00, 0x98, 0xCB, 0x98, 0x4B, 0x93, 0x86, 
    0xA6, 0xAA, 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x63, 0x1F, 0x07, 0x10, 
    0x98, 0x4B, 0x6D, 0x9B, 0x98, 0xCB, 0x93, 0x77, 0x45, 0x00, 0xA9, 0xCB, 0x93, 0x07, 0xF6, 0x07, 
    0x9D, 0x83, 0x2E, 0xC0, 0x2D, 0x68, 0x81, 0x76, 0x3E, 0xC4, 0xB7, 0x08, 0x02, 0x00, 0xB7, 0x27, 
    0x02, 0x40, 0x37, 0x33, 0x00, 0x40, 0x13, 0x08, 0xA8, 0xAA, 0xFD, 0x16, 0x98, 0x4B, 0x33, 0x67,   
    0x17, 0x01, 0x98, 0xCB, 0x02, 0x47, 0xD8, 0xCB, 0x98, 0x4B, 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 
    0xD8, 0x47, 0x05, 0x8B, 0x71, 0xEF, 0x98, 0x4B, 0x75, 0x8F, 0x98, 0xCB, 0x02, 0x47, 0x13, 0x07, 
    0x07, 0x08, 0x3A, 0xC0, 0x22, 0x47, 0x7D, 0x17, 0x3A, 0xC4, 0x69, 0xFB, 0x93, 0x77, 0x85, 0x00, 
    0xED, 0xC3, 0x93, 0x07, 0xF6, 0x07, 0x2E, 0xC0, 0x9D, 0x83, 0x37, 0x27, 0x02, 0x40, 0x3E, 0xC4, 
    0x1C, 0x4B, 0xC1, 0x66, 0x37, 0x08, 0x08, 0x00, 0xD5, 0x8F, 0x1C, 0xCB, 0xA1, 0x48, 0x37, 0x17, 
    0x00, 0x20, 0xB7, 0x27, 0x02, 0x40, 0x37, 0x03, 0x04, 0x00, 0x94, 0x4B, 0xB3, 0xE6, 0x06, 0x01, 
    0x94, 0xCB, 0xD4, 0x47, 0x85, 0x8A, 0xF5, 0xFE, 0x82, 0x46, 0x3A, 0x8E, 0x36, 0xC2, 0x46, 0xC6, 
    0x92, 0x46, 0x83, 0x2E, 0x07, 0x00, 0x41, 0x07, 0x23, 0xA0, 0xD6, 0x01, 0x92, 0x46, 0x83, 0x2E,    
    0x47, 0xFF, 0x23, 0xA2, 0xD6, 0x01, 0x92, 0x46, 0x83, 0x2E, 0x87, 0xFF, 0x23, 0xA4, 0xD6, 0x01, 
    0x92, 0x46, 0x03, 0x2E, 0xCE, 0x00, 0x23, 0xA6, 0xC6, 0x01, 0x94, 0x4B, 0xB3, 0xE6, 0x66, 0x00, 
    0x94, 0xCB, 0xD4, 0x47, 0x85, 0x8A, 0xF5, 0xFE, 0x92, 0x46, 0x3A, 0x8E, 0xC1, 0x06, 0x36, 0xC2, 
    0xB2, 0x46, 0xFD, 0x16, 0x36, 0xC6, 0xCD, 0xFE, 0x82, 0x46, 0xD4, 0xCB, 0x94, 0x4B, 0x93, 0xE6, 
    0x06, 0x04, 0x94, 0xCB, 0xD4, 0x47, 0x85, 0x8A, 0xF5, 0xFE, 0xD4, 0x47, 0xD1, 0x8A, 0x85, 0xC6, 
    0xD8, 0x47, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, 0x13, 0x67, 0x47, 0x01, 0xD8, 0xC7, 0x98, 0x4B, 
    0x21, 0x45, 0x75, 0x8F, 0x98, 0xCB, 0x41, 0x01, 0x02, 0x90, 0x23, 0x20, 0xD8, 0x00, 0xE9, 0xBD, 
    0x23, 0x20, 0x03, 0x01, 0x31, 0xBF, 0x82, 0x46, 0x93, 0x86, 0x06, 0x08, 0x36, 0xC0, 0xA2, 0x46,   
    0xFD, 0x16, 0x36, 0xC4, 0xB9, 0xFA, 0x98, 0x4B, 0xB7, 0x06, 0xF3, 0xFF, 0xFD, 0x16, 0x75, 0x8F, 
    0x98, 0xCB, 0x41, 0x89, 0x15, 0xC9, 0x2E, 0xC0, 0x0D, 0x06, 0x02, 0xC4, 0x09, 0x82, 0x32, 0xC6, 
    0xB7, 0x17, 0x00, 0x20, 0x98, 0x43, 0x13, 0x86, 0x47, 0x00, 0xA2, 0x47, 0x82, 0x46, 0x8A, 0x07, 
    0xB6, 0x97, 0x9C, 0x43, 0x63, 0x1C, 0xF7, 0x00, 0xA2, 0x47, 0x85, 0x07, 0x3E, 0xC4, 0xA2, 0x46, 
    0x32, 0x47, 0xB2, 0x87, 0xE3, 0xE0, 0xE6, 0xFE, 0x01, 0x45, 0x71, 0xBF, 0x41, 0x45, 0x61, 0xBF, 
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
uint8_t flash_op569[ ] ={
0x79,0x71,0x22,0xd4,0x26,0xd2,0x5a,0xc8,0x06,0xd6,0x4a,0xd0,0x4e,0xce,0x52,0xcc,
0x56,0xca,0x5e,0xc6,0x93,0x77,0x15,0x00,0x2a,0x84,0x2e,0x8b,0xb2,0x84,0x9d,0xe7,
0x93,0x77,0x24,0x00,0x99,0xc7,0xb7,0x85,0x07,0x00,0x01,0x45,0x59,0x22,0x89,0x47,
0x15,0xe1,0x93,0x77,0x44,0x00,0x91,0xc7,0x85,0x65,0x5a,0x85,0x9d,0x2a,0x91,0x47,
0x11,0xe9,0x93,0x77,0x84,0x01,0x9d,0xe3,0x81,0x47,0x29,0xa0,0x01,0x45,0xc5,0x26,
0x85,0x47,0x79,0xd5,0xb2,0x50,0x22,0x54,0x92,0x54,0x02,0x59,0xf2,0x49,0x62,0x4a,
0xd2,0x4a,0x42,0x4b,0xb2,0x4b,0x3e,0x85,0x45,0x61,0x02,0x90,0x93,0x84,0xf4,0x0f,
0x93,0x7b,0x84,0x00,0xa1,0x80,0x01,0x49,0xb7,0x1a,0x00,0x20,0x41,0x88,0x93,0x19,
0x89,0x00,0x33,0x8a,0x69,0x01,0x63,0x9e,0x0b,0x00,0x0d,0xc4,0x13,0x06,0x00,0x10,
0xb3,0x85,0x59,0x01,0x52,0x85,0x01,0x2e,0x13,0x75,0xf5,0x0f,0x01,0xcd,0xc1,0x47,
0x55,0xbf,0x13,0x06,0x00,0x10,0xb3,0x85,0x59,0x01,0x52,0x85,0xed,0x22,0x71,0xdd,
0xa1,0x47,0x4d,0xb7,0x05,0x09,0xe3,0x94,0x24,0xfd,0x79,0xb7,0x37,0x17,0x00,0x40,
0x83,0x47,0xa7,0x01,0xe2,0x07,0xe1,0x87,0xe3,0xcc,0x07,0xfe,0x23,0x0d,0x07,0x00,
0x82,0x80,0x37,0x17,0x00,0x40,0x83,0x47,0xa7,0x01,0xe2,0x07,0xe1,0x87,0xe3,0xcc,
0x07,0xfe,0x23,0x0c,0xa7,0x00,0x82,0x80,0x37,0x17,0x00,0x40,0x83,0x47,0xa7,0x01,
0xe2,0x07,0xe1,0x87,0xe3,0xcc,0x07,0xfe,0x03,0x45,0x87,0x01,0x82,0x80,0x41,0x11,
0x22,0xc4,0x2a,0x84,0x41,0x81,0x13,0x75,0xf5,0x0f,0x06,0xc6,0xd9,0x37,0x13,0x55,
0x84,0x00,0x13,0x75,0xf5,0x0f,0x75,0x3f,0x13,0x75,0xf4,0x0f,0x22,0x44,0xb2,0x40,
0x41,0x01,0x45,0xbf,0x01,0x11,0x22,0xcc,0x26,0xca,0x06,0xce,0x37,0x14,0x00,0x40,
0x2a,0xc6,0x23,0x0d,0x04,0x00,0x9d,0x44,0x23,0x0d,0x94,0x00,0x99,0x47,0x23,0x0c,
0xf4,0x00,0xad,0x3f,0x23,0x0d,0x04,0x00,0x23,0x0d,0x94,0x00,0x32,0x45,0x23,0x0c,
0xa4,0x00,0xf2,0x40,0x62,0x44,0xd2,0x44,0x05,0x61,0x82,0x80,0x79,0x71,0x4a,0xd0,
0x37,0x19,0x00,0x40,0x22,0xd4,0x26,0xd2,0x4e,0xce,0x52,0xcc,0x06,0xd6,0x37,0x04,
0x28,0x00,0xa9,0x37,0x93,0x04,0xa9,0x01,0x1d,0x4a,0x95,0x49,0x23,0x80,0x04,0x00,
0x23,0x80,0x44,0x01,0x23,0x0c,0x39,0x01,0x85,0x37,0xb9,0x3f,0x2a,0xc6,0x3d,0x37,
0x32,0x45,0x05,0x89,0x09,0xcd,0x7d,0x14,0x75,0xf0,0x13,0x05,0xf0,0x0f,0xb2,0x50,
0x22,0x54,0x92,0x54,0x02,0x59,0xf2,0x49,0x62,0x4a,0x45,0x61,0x82,0x80,0x01,0x45,
0xfd,0xb7,0xb7,0x16,0x00,0x40,0x03,0xc7,0x46,0x00,0x41,0x8b,0x71,0xeb,0x05,0x67,
0x01,0x11,0x7d,0x17,0x22,0xcc,0x33,0x84,0xe5,0x00,0x69,0x8f,0x26,0xca,0x3a,0x94,
0xfd,0x74,0x65,0x8c,0x06,0xce,0xe9,0x8c,0x4a,0xc8,0x4e,0xc6,0x37,0x06,0x08,0x00,
0xaa,0x87,0x13,0x05,0xe0,0x0f,0x63,0xf7,0xc4,0x06,0x33,0x07,0x94,0x00,0x13,0x05,
0xa0,0x0f,0x63,0x61,0xe6,0x06,0x13,0x07,0x70,0x05,0x23,0x80,0xe6,0x00,0x13,0x07,
0x80,0xfa,0x23,0x80,0xe6,0x00,0x03,0xc7,0x46,0x00,0x3d,0x65,0xe9,0x8f,0x13,0x67,
0xc7,0x08,0x23,0x82,0xe6,0x00,0x91,0xe7,0xb7,0x09,0x07,0x00,0x41,0x69,0x63,0xe2,
0x34,0x05,0xa2,0x94,0x05,0x69,0xb3,0x89,0x84,0x40,0x63,0x79,0x24,0x05,0x01,0x45,
0x37,0x17,0x00,0x40,0x93,0x07,0x70,0x05,0x23,0x00,0xf7,0x00,0x93,0x07,0x80,0xfa,
0x23,0x00,0xf7,0x00,0x83,0x47,0x47,0x00,0x93,0xf7,0x37,0x07,0x93,0xe7,0x07,0x08,
0x23,0x02,0xf7,0x00,0xf2,0x40,0x62,0x44,0xd2,0x44,0x42,0x49,0xb2,0x49,0x05,0x61,
0x82,0x80,0xe3,0x60,0x24,0xfd,0x13,0x05,0x80,0x0d,0x6d,0x3d,0x26,0x85,0x41,0x3d,
0xf5,0x35,0x5d,0xfd,0xca,0x94,0x33,0x04,0x24,0x41,0x55,0xb7,0x13,0x05,0x00,0x02,
0x55,0x35,0x4e,0x85,0xad,0x3d,0xd9,0x3d,0x45,0xf5,0x33,0x04,0x24,0x41,0x61,0xbf,
0x13,0x05,0xb0,0x0f,0x82,0x80,0x01,0x11,0x22,0xcc,0x37,0x04,0x00,0x10,0x71,0x14,
0x69,0x8c,0x21,0x65,0x2a,0x94,0x06,0xce,0x26,0xca,0x4a,0xc8,0x4e,0xc6,0x37,0x07,
0x08,0x00,0x13,0x05,0xe0,0x0f,0x63,0x71,0xe4,0x0e,0xb3,0x07,0xc4,0x00,0x13,0x05,
0xa0,0x0f,0x63,0x6b,0xf7,0x0c,0xb7,0x17,0x00,0x40,0x03,0xc7,0x47,0x00,0x13,0x05,
0xb0,0x0f,0x41,0x8b,0x71,0xe3,0x13,0x07,0x70,0x05,0x23,0x80,0xe7,0x00,0x13,0x07,
0x80,0xfa,0x23,0x80,0xe7,0x00,0x03,0xc7,0x47,0x00,0x2e,0x89,0x93,0x59,0x26,0x00,
0x13,0x67,0xc7,0x08,0x23,0x82,0xe7,0x00,0xb7,0x14,0x00,0x40,0x63,0x94,0x09,0x00,
0x01,0x45,0x8d,0xa8,0x09,0x45,0x39,0x3d,0x22,0x85,0xd5,0x3b,0x33,0x05,0x24,0x41,
0x11,0x09,0x83,0x27,0xc9,0xff,0xdc,0xc8,0x83,0xc7,0xa4,0x01,0x93,0xe7,0x07,0x01,
0x03,0xc7,0xa4,0x01,0x62,0x07,0x61,0x87,0xe3,0x4c,0x07,0xfe,0x23,0x8d,0xf4,0x00,
0x03,0xc7,0xa4,0x01,0x62,0x07,0x61,0x87,0xe3,0x4c,0x07,0xfe,0x23,0x8d,0xf4,0x00,
0x03,0xc7,0xa4,0x01,0x62,0x07,0x61,0x87,0xe3,0x4c,0x07,0xfe,0x23,0x8d,0xf4,0x00,
0x03,0xc7,0xa4,0x01,0x62,0x07,0x61,0x87,0xe3,0x4c,0x07,0xfe,0x23,0x8d,0xf4,0x00,
0xfd,0x19,0x33,0x04,0xa9,0x00,0x63,0x85,0x09,0x00,0x93,0x77,0xf4,0x0f,0xcd,0xf3,
0xf5,0x33,0x49,0xd5,0x37,0x17,0x00,0x40,0x93,0x07,0x70,0x05,0x23,0x00,0xf7,0x00,
0x93,0x07,0x80,0xfa,0x23,0x00,0xf7,0x00,0x83,0x47,0x47,0x00,0x93,0xf7,0x37,0x07,
0x93,0xe7,0x07,0x08,0x23,0x02,0xf7,0x00,0xf2,0x40,0x62,0x44,0xd2,0x44,0x42,0x49,
0xb2,0x49,0x05,0x61,0x82,0x80,0x01,0x11,0xa1,0x67,0x26,0xca,0x3e,0x95,0x06,0xce,
0x22,0xcc,0x4a,0xc8,0x4e,0xc6,0x52,0xc4,0xb7,0x07,0x08,0x00,0x93,0x04,0xe0,0x0f,
0x63,0x71,0xf5,0x04,0xb7,0x17,0x00,0x40,0x03,0xc7,0x47,0x00,0x93,0x04,0xb0,0x0f,
0x41,0x8b,0x05,0xeb,0x23,0x8d,0x07,0x00,0x1d,0x47,0x23,0x8d,0xe7,0x00,0x2d,0x47,
0x23,0x8c,0xe7,0x00,0x2e,0x84,0x93,0x54,0x26,0x00,0x11,0x3b,0xf5,0x39,0xed,0x39,
0xfd,0x59,0x37,0x1a,0x00,0x40,0x13,0x89,0xf4,0xff,0x63,0x1d,0x39,0x01,0x81,0x44,
0x75,0x39,0xf2,0x40,0x62,0x44,0x26,0x85,0x42,0x49,0xd2,0x44,0xb2,0x49,0x22,0x4a,
0x05,0x61,0x82,0x80,0xd1,0x39,0xc9,0x39,0xc1,0x39,0xf9,0x31,0x11,0x04,0x03,0x27,
0x4a,0x01,0x83,0x27,0xc4,0xff,0xe3,0x1d,0xf7,0xfc,0xca,0x84,0xe9,0xb7,0x79,0x71,
0x4a,0xd0,0x37,0x19,0x00,0x40,0x22,0xd4,0x26,0xd2,0x4e,0xce,0x52,0xcc,0x06,0xd6,
0x37,0x04,0x28,0x00,0xa5,0x39,0x93,0x04,0xa9,0x01,0x1d,0x4a,0x95,0x49,0x23,0x80,
0x04,0x00,0x23,0x80,0x44,0x01,0x23,0x0c,0x39,0x01,0x79,0x31,0x71,0x31,0x2a,0xc6,
0xb1,0x39,0x32,0x45,0x93,0x77,0x15,0x00,0xa9,0xc3,0x7d,0x14,0x6d,0xf0,0x13,0x05,
0xf0,0x0f,0xb2,0x50,0x22,0x54,0x92,0x54,0x02,0x59,0xf2,0x49,0x62,0x4a,0x45,0x61,
0x82,0x80,0x13,0x07,0x40,0x04,0x01,0x45,0xe3,0x85,0xe7,0xfe,0x05,0x45,0x59,0x39,
0x13,0x05,0x40,0x04,0x3d,0x39,0x09,0x45,0x2d,0x39,0x22,0x54,0xb2,0x50,0x92,0x54,
0x02,0x59,0xf2,0x49,0x62,0x4a,0x45,0x61,0x55,0xb9,0x93,0x77,0xc5,0x07,0xf1,0xfb,
0x01,0x45,0xc1,0xb7,
};
uint8_t flash_op573[ ] ={
    0x79, 0x71, 0x22, 0xD4, 0x26, 0xD2, 0x5A, 0xC8, 0x06, 0xD6, 0x4A, 0xD0, 0x4E, 0xCE, 0x52, 0xCC, 
    0x56, 0xCA, 0x5E, 0xC6, 0x93, 0x77, 0x15, 0x00, 0x2A, 0x84, 0x2E, 0x8B, 0xB2, 0x84, 0x9D, 0xEF, 
    0x93, 0x77, 0x24, 0x00, 0x99, 0xCB, 0xB7, 0x86, 0x07, 0x00, 0x01, 0x46, 0x81, 0x45, 0x05, 0x45, 
    0x9D, 0x22, 0x93, 0x77, 0xF5, 0x0F, 0x09, 0x45, 0x9D, 0xEB, 0x93, 0x77, 0x44, 0x00, 0x91, 0xCB, 
    0x85, 0x66, 0x01, 0x46, 0xDA, 0x85, 0x05, 0x45, 0xB9, 0x22, 0x93, 0x77, 0xF5, 0x0F, 0x11, 0x45, 
    0x99, 0xEF, 0x93, 0x77, 0x84, 0x01, 0x9D, 0xE7, 0x01, 0x45, 0x11, 0xA8, 0x81, 0x46, 0x01, 0x46, 
    0x81, 0x45, 0x21, 0x45, 0x0D, 0x2A, 0x93, 0x77, 0xF5, 0x0F, 0x05, 0x45, 0xD5, 0xDB, 0xB2, 0x50, 
    0x22, 0x54, 0x92, 0x54, 0x02, 0x59, 0xF2, 0x49, 0x62, 0x4A, 0xD2, 0x4A, 0x42, 0x4B, 0xB2, 0x4B, 
    0x45, 0x61, 0x02, 0x90, 0x93, 0x84, 0xF4, 0x0F, 0x93, 0x7B, 0x84, 0x00, 0xA1, 0x80, 0x01, 0x49, 
    0xB7, 0x5A, 0x00, 0x20, 0x41, 0x88, 0x93, 0x19, 0x89, 0x00, 0x33, 0x8A, 0x69, 0x01, 0x63, 0x9F, 
    0x0B, 0x00, 0x0D, 0xC8, 0x93, 0x06, 0x00, 0x10, 0x33, 0x86, 0x59, 0x01, 0xD2, 0x85, 0x0D, 0x45, 
    0xDD, 0x20, 0x13, 0x75, 0xF5, 0x0F, 0x19, 0xCD, 0x41, 0x45, 0x55, 0xBF, 0x93, 0x06, 0x00, 0x10, 
    0x33, 0x86, 0x59, 0x01, 0xD2, 0x85, 0x09, 0x45, 0xF9, 0x20, 0x13, 0x75, 0xF5, 0x0F, 0x71, 0xD9, 
    0x21, 0x45, 0x71, 0xBF, 0x05, 0x09, 0xE3, 0x10, 0x99, 0xFC, 0xBD, 0xBF, 0x23, 0x03, 0x04, 0x80, 
    0x95, 0x47, 0x23, 0x03, 0xF4, 0x80, 0x23, 0x02, 0xA4, 0x80, 0x82, 0x80, 0x83, 0x07, 0x64, 0x80, 
    0xE3, 0xCE, 0x07, 0xFE, 0x23, 0x03, 0x04, 0x80, 0x82, 0x80, 0x83, 0x07, 0x64, 0x80, 0xE3, 0xCE, 
    0x07, 0xFE, 0x03, 0x45, 0x44, 0x80, 0x82, 0x80, 0x83, 0x07, 0x64, 0x80, 0xE3, 0xCE, 0x07, 0xFE, 
    0x23, 0x02, 0xA4, 0x80, 0x82, 0x80, 0x41, 0x11, 0x26, 0xC4, 0x4A, 0xC2, 0x4E, 0xC0, 0x06, 0xC6, 
    0x13, 0x77, 0xF5, 0x0B, 0xAD, 0x47, 0xAA, 0x89, 0x2E, 0x89, 0x95, 0x44, 0x63, 0x06, 0xF7, 0x00, 
    0x19, 0x45, 0x6D, 0x37, 0x65, 0x3F, 0x8D, 0x44, 0x4E, 0x85, 0x4D, 0x37, 0xFD, 0x59, 0xFD, 0x14, 
    0x63, 0x98, 0x34, 0x01, 0xB2, 0x40, 0xA2, 0x44, 0x12, 0x49, 0x82, 0x49, 0x41, 0x01, 0x82, 0x80, 
    0x13, 0x55, 0x09, 0x01, 0x13, 0x75, 0xF5, 0x0F, 0x45, 0x3F, 0x22, 0x09, 0xCD, 0xB7, 0x01, 0x11, 
    0x26, 0xCC, 0x06, 0xCE, 0xB7, 0x04, 0x08, 0x00, 0x51, 0x37, 0x15, 0x45, 0x85, 0x3F, 0x71, 0x37, 
    0x69, 0x37, 0x2A, 0xC6, 0xA5, 0x3F, 0x32, 0x45, 0x93, 0x77, 0x15, 0x00, 0x89, 0xEB, 0x13, 0x65, 
    0x15, 0x00, 0x13, 0x75, 0xF5, 0x0F, 0xF2, 0x40, 0xE2, 0x44, 0x05, 0x61, 0x82, 0x80, 0xFD, 0x14, 
    0xE9, 0xFC, 0x01, 0x45, 0xCD, 0xBF, 0x39, 0x71, 0x26, 0xDC, 0x4A, 0xDA, 0x4E, 0xD8, 0x52, 0xD6, 
    0x56, 0xD4, 0x5A, 0xD2, 0x5E, 0xD0, 0x06, 0xDE, 0x62, 0xCE, 0x66, 0xCC, 0xB7, 0xE7, 0x00, 0xE0, 
    0x7D, 0x57, 0x83, 0xAA, 0x07, 0x00, 0x22, 0xC6, 0x03, 0xAA, 0x47, 0x00, 0x23, 0xA0, 0xE7, 0x18, 
    0x23, 0xA2, 0xE7, 0x18, 0xB7, 0x17, 0x00, 0x40, 0x13, 0x07, 0x70, 0x05, 0x23, 0x80, 0xE7, 0x04, 
    0x13, 0x07, 0x80, 0xFA, 0x23, 0x80, 0xE7, 0x04, 0x83, 0xC7, 0x47, 0x04, 0x13, 0x09, 0x75, 0xFF, 
    0xB6, 0x84, 0xE2, 0x07, 0x13, 0x79, 0xF9, 0x0F, 0x85, 0x46, 0xAA, 0x89, 0xAE, 0x8B, 0x32, 0x8B, 
    0x37, 0x24, 0x00, 0x40, 0xE1, 0x87, 0x01, 0x57, 0x63, 0xFA, 0x26, 0x01, 0x63, 0x08, 0xD5, 0x00,  
    0x89, 0x46, 0x13, 0x07, 0x00, 0x02, 0x63, 0x13, 0xD5, 0x00, 0x01, 0x57, 0xD9, 0x8F, 0x93, 0xF7, 
    0xF7, 0x0F, 0xB7, 0x1C, 0x00, 0x40, 0x23, 0x82, 0xFC, 0x04, 0x11, 0x47, 0x23, 0x03, 0xE4, 0x80, 
    0x13, 0x05, 0xF0, 0x0F, 0x65, 0x3D, 0x09, 0x4C, 0xD1, 0x35, 0x63, 0x69, 0x2C, 0x11, 0xB7, 0x07, 
    0x07, 0x00, 0xBE, 0x9B, 0x37, 0x87, 0x07, 0x00, 0x79, 0x55, 0x63, 0xFE, 0xEB, 0x02, 0xB3, 0x87, 
    0x9B, 0x00, 0x63, 0x6A, 0xF7, 0x02, 0xA9, 0x47, 0x63, 0x99, 0xF9, 0x06, 0x89, 0xE4, 0x81, 0x44, 
    0x71, 0x3D, 0x26, 0x85, 0x0D, 0xA0, 0xDE, 0x85, 0x09, 0x45, 0x75, 0x3D, 0x05, 0x0B, 0x03, 0x45, 
    0xFB, 0xFF, 0xFD, 0x14, 0x85, 0x0B, 0x4D, 0x35, 0x81, 0xC4, 0x93, 0xF7, 0xFB, 0x0F, 0xFD, 0xF7, 
    0xFD, 0x35, 0x69, 0xFD, 0x7D, 0x55, 0xB7, 0x17, 0x00, 0x40, 0x13, 0x07, 0x70, 0x05, 0x23, 0x80, 
    0xE7, 0x04, 0x13, 0x07, 0x80, 0xFA, 0x23, 0x80, 0xE7, 0x04, 0x03, 0xC7, 0x47, 0x04, 0x41, 0x8B, 
    0x23, 0x82, 0xE7, 0x04, 0xF2, 0x50, 0xB7, 0xE7, 0x00, 0xE0, 0x23, 0xA0, 0x57, 0x11, 0x23, 0xA2, 
    0x47, 0x11, 0xE2, 0x54, 0x32, 0x44, 0x52, 0x59, 0xC2, 0x59, 0x32, 0x5A, 0xA2, 0x5A, 0x12, 0x5B, 
    0x82, 0x5B, 0x72, 0x4C, 0xE2, 0x4C, 0x21, 0x61, 0x82, 0x80, 0xA5, 0x47, 0x63, 0x95, 0xF9, 0x06, 
    0x85, 0x69, 0x13, 0x09, 0xF0, 0x0F, 0xB3, 0x06, 0x99, 0x00, 0xB3, 0xF4, 0x2B, 0x01, 0xB6, 0x94, 
    0x13, 0x49, 0xF9, 0xFF, 0xB3, 0x74, 0x99, 0x00, 0x41, 0x6B, 0x33, 0x79, 0x79, 0x01, 0x85, 0x6B, 
    0x93, 0x87, 0xF9, 0xFF, 0xB3, 0xF7, 0x27, 0x01, 0x99, 0xE3, 0x63, 0xFC, 0x34, 0x01, 0x93, 0xD9, 
    0x49, 0x00, 0xC1, 0x47, 0xE3, 0xE6, 0x37, 0xFF, 0x99, 0xBF, 0x05, 0x69, 0xC1, 0x69, 0x7D, 0x19,  
    0xD9, 0xB7, 0x13, 0x05, 0x80, 0x0D, 0x63, 0x88, 0x69, 0x01, 0x13, 0x05, 0x00, 0x02, 0x63, 0x84, 
    0x79, 0x01, 0x13, 0x05, 0x10, 0x08, 0xCA, 0x85, 0xFD, 0x3B, 0x91, 0x35, 0x21, 0xDD, 0x4E, 0x99, 
    0xB3, 0x84, 0x34, 0x41, 0xD9, 0xB7, 0xDE, 0x85, 0x2D, 0x45, 0xF5, 0x33, 0xDA, 0x94, 0xE3, 0x00, 
    0x9B, 0xF2, 0x05, 0x0B, 0xD9, 0x33, 0xA3, 0x0F, 0xAB, 0xFE, 0xD5, 0xBF, 0x93, 0x87, 0xF9, 0xFF, 
    0x93, 0xF7, 0xF7, 0x0F, 0x63, 0x6C, 0xFC, 0x08, 0x03, 0xC7, 0x5C, 0x04, 0xB7, 0x07, 0x08, 0x00, 
    0x13, 0x77, 0x07, 0x02, 0x19, 0xE3, 0xB7, 0x87, 0x07, 0x00, 0x79, 0x55, 0xE3, 0xFD, 0xFB, 0xF0, 
    0x33, 0x87, 0x9B, 0x00, 0xE3, 0xE9, 0xE7, 0xF0, 0x89, 0x47, 0x63, 0x90, 0xF9, 0x04, 0x89, 0x80, 
    0x55, 0x49, 0xE3, 0x8E, 0x04, 0xEC, 0xDE, 0x85, 0x09, 0x45, 0x71, 0x3B, 0x11, 0x0B, 0x03, 0x27, 
    0xCB, 0xFF, 0x91, 0x47, 0x23, 0x20, 0xE4, 0x80, 0x03, 0x07, 0x64, 0x80, 0xE3, 0x4E, 0x07, 0xFE, 
    0x23, 0x03, 0x24, 0x81, 0xFD, 0x17, 0xED, 0xFB, 0xFD, 0x14, 0x91, 0x0B, 0x81, 0xC4, 0x93, 0xF7, 
    0xFB, 0x0F, 0xE9, 0xFF, 0x6D, 0x3B, 0x71, 0xF5, 0xF1, 0xB5, 0x85, 0x47, 0xE3, 0x87, 0xF9, 0xF4, 
    0xDE, 0x85, 0x2D, 0x45, 0x8D, 0x33, 0x13, 0x89, 0xF4, 0xFF, 0xE3, 0x8A, 0x04, 0xE8, 0x35, 0x3B, 
    0x93, 0x77, 0x39, 0x00, 0x91, 0xEB, 0x83, 0x26, 0x04, 0x80, 0x03, 0x27, 0x0B, 0x00, 0x93, 0x07, 
    0x4B, 0x00, 0xE3, 0x9F, 0xE6, 0xE6, 0x3E, 0x8B, 0xCA, 0x84, 0xF1, 0xBF, 0xA1, 0x47, 0x63, 0x92, 
    0xF9, 0x04, 0xB5, 0x3B, 0x81, 0x44, 0x63, 0x8D, 0x0B, 0x00, 0x8D, 0x47, 0x93, 0x04, 0xC0, 0x03, 
    0x63, 0x88, 0xFB, 0x00, 0x93, 0x04, 0x00, 0x05, 0x63, 0x84, 0x8B, 0x01, 0x93, 0x04, 0x40, 0x04, 
    0x13, 0x75, 0xC5, 0x07, 0xE3, 0x05, 0x95, 0xE4, 0x19, 0x45, 0xC9, 0x39, 0xC5, 0x31, 0x05, 0x45, 
    0xF1, 0x31, 0x26, 0x85, 0xD5, 0x39, 0x09, 0x45, 0xC5, 0x39, 0x91, 0x33, 0xE3, 0x19, 0x05, 0xE2, 
    0x91, 0xBD, 0xE3, 0x86, 0x09, 0xE2, 0xF1, 0x54, 0x25, 0xB5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
uint8_t flash_op307[ ] ={
	0x93, 0x77, 0x15, 0x00, 0x41, 0x11, 0x99, 0xcf, 0xb7, 0x06, 0x67, 0x45, 0xb7, 0x27, 0x02, 0x40, 
	0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xef, 0xcd, 0xd4, 0xc3, 0x13, 0x07, 0xb7, 0x9a, 0xd8, 0xc3, 
	0xd4, 0xd3, 0xd8, 0xd3, 0x93, 0x77, 0x25, 0x00, 0x95, 0xc7, 0xb7, 0x27, 0x02, 0x40, 0x98, 0x4b, 
	0xad, 0x66, 0x37, 0x38, 0x00, 0x40, 0x13, 0x67, 0x47, 0x00, 0x98, 0xcb, 0x98, 0x4b, 0x93, 0x86, 
	0xa6, 0xaa, 0x13, 0x67, 0x07, 0x04, 0x98, 0xcb, 0xd8, 0x47, 0x05, 0x8b, 0x61, 0xeb, 0x98, 0x4b, 
	0x6d, 0x9b, 0x98, 0xcb, 0x93, 0x77, 0x45, 0x00, 0xa9, 0xcb, 0x93, 0x07, 0xf6, 0x0f, 0xa1, 0x83, 
	0x2e, 0xc0, 0x2d, 0x68, 0x81, 0x76, 0x3e, 0xc4, 0xb7, 0x08, 0x02, 0x00, 0xb7, 0x27, 0x02, 0x40, 
	0x37, 0x33, 0x00, 0x40, 0x13, 0x08, 0xa8, 0xaa, 0xfd, 0x16, 0x98, 0x4b, 0x33, 0x67, 0x17, 0x01, 	
	0x98, 0xcb, 0x02, 0x47, 0xd8, 0xcb, 0x98, 0x4b, 0x13, 0x67, 0x07, 0x04, 0x98, 0xcb, 0xd8, 0x47, 
	0x05, 0x8b, 0x41, 0xeb, 0x98, 0x4b, 0x75, 0x8f, 0x98, 0xcb, 0x02, 0x47, 0x13, 0x07, 0x07, 0x10, 
	0x3a, 0xc0, 0x22, 0x47, 0x7d, 0x17, 0x3a, 0xc4, 0x69, 0xfb, 0x93, 0x77, 0x85, 0x00, 0xd5, 0xcb, 
	0x93, 0x07, 0xf6, 0x0f, 0x2e, 0xc0, 0xa1, 0x83, 0x3e, 0xc4, 0x37, 0x27, 0x02, 0x40, 0x1c, 0x4b, 
	0xc1, 0x66, 0x41, 0x68, 0xd5, 0x8f, 0x1c, 0xcb, 0xb7, 0x16, 0x00, 0x20, 0xb7, 0x27, 0x02, 0x40, 
	0x93, 0x08, 0x00, 0x04, 0x37, 0x03, 0x20, 0x00, 0x98, 0x4b, 0x33, 0x67, 0x07, 0x01, 0x98, 0xcb, 
	0xd8, 0x47, 0x05, 0x8b, 0x75, 0xff, 0x02, 0x47, 0x3a, 0xc2, 0x46, 0xc6, 0x32, 0x47, 0x0d, 0xef, 
	0x98, 0x4b, 0x33, 0x67, 0x67, 0x00, 0x98, 0xcb, 0xd8, 0x47, 0x05, 0x8b, 0x75, 0xff, 0xd8, 0x47, 	
	0x41, 0x8b, 0x39, 0xc3, 0xd8, 0x47, 0xc1, 0x76, 0xfd, 0x16, 0x13, 0x67, 0x07, 0x01, 0xd8, 0xc7, 
	0x98, 0x4b, 0x21, 0x45, 0x75, 0x8f, 0x98, 0xcb, 0x41, 0x01, 0x02, 0x90, 0x23, 0x20, 0xd8, 0x00, 
	0x25, 0xb7, 0x23, 0x20, 0x03, 0x01, 0xa5, 0xb7, 0x12, 0x47, 0x13, 0x8e, 0x46, 0x00, 0x94, 0x42, 
	0x14, 0xc3, 0x12, 0x47, 0x11, 0x07, 0x3a, 0xc2, 0x32, 0x47, 0x7d, 0x17, 0x3a, 0xc6, 0xd8, 0x47, 
	0x09, 0x8b, 0x75, 0xff, 0xf2, 0x86, 0x5d, 0xb7, 0x02, 0x47, 0x13, 0x07, 0x07, 0x10, 0x3a, 0xc0, 
	0x22, 0x47, 0x7d, 0x17, 0x3a, 0xc4, 0x49, 0xf3, 0x98, 0x4b, 0xc1, 0x76, 0xfd, 0x16, 0x75, 0x8f, 
	0x98, 0xcb, 0x41, 0x89, 0x15, 0xc9, 0x2e, 0xc0, 0x0d, 0x06, 0x02, 0xc4, 0x09, 0x82, 0x32, 0xc6, 
	0xb7, 0x17, 0x00, 0x20, 0x98, 0x43, 0x13, 0x86, 0x47, 0x00, 0xa2, 0x47, 0x82, 0x46, 0x8a, 0x07, 	
	0xb6, 0x97, 0x9c, 0x43, 0x63, 0x1c, 0xf7, 0x00, 0xa2, 0x47, 0x85, 0x07, 0x3e, 0xc4, 0xa2, 0x46, 
	0x32, 0x47, 0xb2, 0x87, 0xe3, 0xe0, 0xe6, 0xfe, 0x01, 0x45, 0xbd, 0xbf, 0x41, 0x45, 0xad, 0xbf, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,   
};
void wlink_ramcodewrite(uint8_t *buffer, int size);
void wlink_getromram(uint32_t *rom,uint32_t *ram){
	
	unsigned char txbuf[4];
	unsigned char rxbuf[4];
	unsigned long len = 4;
	bool type_A=false;
	bool type_B=false;
	bool type_C=false;
	txbuf[0] = 0x81;
	txbuf[1] = 0x0d;
	txbuf[2] = 0x01;
	txbuf[3] = 0x04;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	
	if(chip_type==0x30700518 ||chip_type==0x30710518 ||chip_type==0x30730518 ||chip_type==0x30300514 ||chip_type==0x30310514)
		type_A=true;
	if(chip_type==0x30720518||chip_type==0x30740518)
		type_C=true;
	if(chip_type==0x2034051c||chip_type==0x2080051c||chip_type==0x2081051c||chip_type==0x2082051c||chip_type==0x2083051c)
		type_B=true;
	switch(rxbuf[3]){
		case 0:
			 if(type_B){
				 *rom=128;
                 *ram=64;
			 }
			else if(type_A){
				 *rom=192;
                 *ram=128;
			 }
			else if(type_C){
				 *rom=192;
                 *ram=128;
			}
			else if(riscvchip==3){
				 *rom=96;
                 *ram=32;
			}else{
 				 *rom=0;
                 *ram=0;
			}
			break;
		case 1:
			 if(type_B){
				 *rom=144;
                 *ram=48;
			 }
			else if(type_A){
				 *rom=224;
                 *ram=96;
			 }
			else if(type_C){
				 *rom=224;
                 *ram=96;
			}
			else if(riscvchip==3){
				 *rom=64;
                 *ram=64;				 
			}else{
 				 *rom=0;
                 *ram=0;
			}
			break;
		case 2:
			 if(type_B){
				 *rom=160;
                 *ram=32;
			 }
			else if(type_A){
				 *rom=256;
                 *ram=64;
			 }
			else if(type_C){
				 *rom=0;
                 *ram=0;
			}else{
 				 *rom=0;
                 *ram=0;
			}
			break;
		case 3:
			 if(type_B){
				 *rom=160;
                 *ram=32;
			 }
			else if(type_A){
				 *rom=288;
                 *ram=32;
			 }
			else if(type_C){
				 *rom=0;
                 *ram=0;
			}
			else if(riscvchip==3){
				 *rom=32;
                 *ram=96;
			}else{
 				 *rom=0;
                 *ram=0;
			}
			break;
		default:
				 *rom=0;
                 *ram=0;
			  break;
	}

}
void readmcause();
unsigned char DMI_OP(	  
	unsigned long iIndex, 
	unsigned char iAddr,
	unsigned long iData,
	unsigned char iOP,
	unsigned char *oAddr,
	unsigned long *oData,
	unsigned char *oOP)
{
	unsigned char Txbuf[9];
	unsigned char Rxbuf[9];
	unsigned long len;
	unsigned char *pData;
	unsigned char retrytime;
	Txbuf[0] = 0x81;
	Txbuf[1] = 0x08;
	Txbuf[2] = 0x06;
	Txbuf[3] = iAddr;
	Txbuf[4] = (unsigned char)(iData >> 24);
	Txbuf[5] = (unsigned char)(iData >> 16);
	Txbuf[6] = (unsigned char)(iData >> 8);
	Txbuf[7] = (unsigned char)(iData);
	Txbuf[8] = iOP;
	retrytime = 0;
RETRY:
	len = 9;
	if (pWriteData(gIndex, 1, Txbuf, &len))
	{
		memset(Rxbuf, 0, sizeof(Rxbuf));
		len = 9;
		
		if (pReadData(gIndex, 1, Rxbuf, &len))
		{
			
			*oAddr = Rxbuf[3];
			if (oData)
			{
				pData = (unsigned char *)oData;
				*pData = Rxbuf[7];
				*(pData + 1) = Rxbuf[6];
				*(pData + 2) = Rxbuf[5];
				*(pData + 3) = Rxbuf[4];
			}
			*oOP = Rxbuf[8];
		
			retrytime++;

			if (Rxbuf[8] == 2 && Rxbuf[6] == 3)
			{
				readmcause();
			}

			return true;
		}
	}
	return false;
}

int  wlink_reset()
{
	unsigned char txbuf[4];
	unsigned char rxbuf[4];
	unsigned long len = 4;
	txbuf[0] = 0x81;
	txbuf[1] = 0x0b;
	txbuf[2] = 0x01;	
	txbuf[3] = 0x03;
	unsigned char oAddr;
	unsigned long oData;
	unsigned char oOP;
	unsigned char iAddr;
	if(riscvchip==0x2)
		txbuf[3]=0x02;
	DMI_OP(0, 0x10, 0x80000001, 2, &oAddr, &oData, &oOP);
	usleep(1000);
	oAddr = 0;
	oData = 0;
	oOP = 0;
	iAddr = 0;
	DMI_OP(0, 0x11, iAddr, 1, &oAddr, &oData, &oOP);
	usleep(1000);
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	usleep(1000);
	usleep(1000);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	DMI_OP(0, 0x10, 0x80000001, 2, &oAddr, &oData, &oOP);
	usleep(1000);
	DMI_OP(0, 0x11, iAddr, 1, &oAddr, &oData, &oOP);
	return 0;
}
int wlink_quitreset(void)
{
	unsigned char txbuf[4];
	unsigned char rxbuf[4];
	unsigned long len = 4;
	txbuf[0] = 0x81;
	txbuf[1] = 0x0b;
	txbuf[2] = 0x01;
	txbuf[3] = 0x01;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	usleep(300000);
	return 0;
}
int wlink_ready_write(uint32_t address,uint32_t count)
{
	
	unsigned char txbuf[24];
	unsigned char rxbuf[24];
	unsigned long len = 4;
	unsigned long chipiaddr1 = chipiaddr + address;
	txbuf[0] = 0x81;
	txbuf[1] = 0x02;
	txbuf[2] = 0x01;
	txbuf[3] = 0x06;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	txbuf[0] = 0x81;
	txbuf[1] = 0x01;
	txbuf[2] = 0x08;
	txbuf[3] = (uint8_t)(chipiaddr1 >> 24);
	txbuf[4] = (uint8_t)(chipiaddr1 >> 16);
	txbuf[5] = (uint8_t)(chipiaddr1 >> 8);
	txbuf[6] = (uint8_t)chipiaddr1;
	txbuf[7] = (uint8_t)(count >> 24);
	txbuf[8] = (uint8_t)(count >> 16);
	txbuf[9] = (uint8_t)(count >> 8);
	txbuf[10]= (uint8_t)count;
	len = 11;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	txbuf[0] = 0x81;
	txbuf[1] = 0x02;
	txbuf[2] = 0x01;
	txbuf[3] = 0x05;
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	switch (riscvchip)
	{
	case 3:
		wlink_ramcodewrite(flash_op569, sizeof(flash_op569));
		break;
	case 1:
		wlink_ramcodewrite(flash_op103, sizeof(flash_op103));
		break;
	case 2:
		wlink_ramcodewrite(flash_op573, sizeof(flash_op573));
		break;
	case 5:
	case 6:
		wlink_ramcodewrite(flash_op307, sizeof(flash_op307));
		break;
	default:;
	}
	txbuf[0] = 0x81;
	txbuf[1] = 0x02;
	txbuf[2] = 0x01;
	txbuf[3] = 0x07;
	if ((riscvchip == 0x1) ||(pageerase))
	{
		txbuf[3] = 0x0b;
	}
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	return rxbuf[3];
}

void wlink_ramcodewrite(uint8_t *buffer, int size)
{
	unsigned long len = 64;
	int i = 0;
	while (size >= 64)
	{
		pWriteData(0, 2, buffer + 64 * i, &len);
		size -= 64;
		i++;
	}
	if (size)
	{
		len = size;
		pWriteData(0, 2, buffer + 64 * i, &len);
	}
}
void wlink_endprogram(void)
{
	unsigned char txbuf[4];
	unsigned char rxbuf[4];
	unsigned long len = 4;
	txbuf[0] = 0x81;
	txbuf[1] = 0x02;
	txbuf[2] = 0x01;
	txbuf[3] = 0x08;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
}

int wlink_fastprogram(uint8_t *buffer)
{
	unsigned long len = 64;
	unsigned char rxbuf[4];
	for (int i = 0; i < 64; i++)
	{
		pWriteData(0, 2, (buffer + i * 64), &len);
		len = 64;
	}
	// usleep(1000);
	// for (int i = 0; i < 4 * 1024; i++)
	// {
	// 	buffer[i] = 0xff;
	// }
	if(pReadData(0, 2, rxbuf, &len)){
		return ERROR_OK;
	}
	return ERROR_FAIL;
}



unsigned char WriteNonFullPage(unsigned long iaddr,
							   unsigned char *ibuff,
							   unsigned long ilen)
{
	unsigned char Txbuf[pagesize];
	unsigned char Rxbuf[pagesize];
	unsigned long len;
	unsigned char *pData;
	unsigned char retrytime;
	unsigned char i = 0;
	Txbuf[0] = 0x81;
	Txbuf[1] = 0x0A;
	Txbuf[2] = 0x05;
	iaddr += chipiaddr;
	Txbuf[3] = (unsigned char)(iaddr >> 24);
	Txbuf[4] = (unsigned char)(iaddr >> 16);
	Txbuf[5] = (unsigned char)(iaddr >> 8);
	Txbuf[6] = (unsigned char)(iaddr);
	Txbuf[7] = (unsigned char)ilen;
	retrytime = 0;
	len = 8;
	if ((riscvchip == 0x03) || (riscvchip == 0x02))
	{
		if (pWriteData(0, 1, Txbuf, &len))
		{
			memset(Rxbuf, 0, sizeof(Rxbuf));
			len = 9;
			if (pReadData(0, 1, Rxbuf, &len))
			{
				if (ilen <= 64)
				{
					len = ilen;
					if (pWriteData(0, 2, ibuff, &len))
					{
					}
					len = 4;
					if (pReadData(0, 2, Rxbuf, &len))
					{
					}
					return 1;
				}
				while (ilen > 64)
				{
					len = 64;
					pWriteData(0, 2, &ibuff[i], &len);
					ilen = ilen - 64;
					i = i + 64;
				}
				if (ilen)
				{
					pWriteData(0, 2, &ibuff[i], &ilen);
				}
				len = 4;
				pReadData(0, 2, Rxbuf, &len);
			}
			return 1;
		}
		return 0;
	}

	if ((riscvchip == 0x01) || (riscvchip == 0x06)||(riscvchip == 0x05))
	{
		if (pWriteData(0, 1, Txbuf, &len))
		{
			memset(Rxbuf, 0, sizeof(Rxbuf));
			len = 9;
			if (pReadData(0, 1, Rxbuf, &len))
			{
				if (ilen <= 64)
				{
					len = ilen;
					if (pWriteData(0, 2, ibuff, &len))
					{
					}
					len = 4;
					if (pReadData(0, 2, Rxbuf, &len))
					{
					}
				}
				else
				{
					len = 64;
					if (pWriteData(0, 2, ibuff, &len))
					{
					}
					len = ilen - 64;
					if (pWriteData(0, 2, &ibuff[64], &len))
					{
					}
					len = 4;
					if (pReadData(0, 2, Rxbuf, &len))
					{
					}
				}
				return 1;
			}
		}
		return 0;
	}
}
int wlink_verify(unsigned long length, unsigned char *buffer)
{
	unsigned char txbuf[12];
	unsigned char rxbuf[12];
	unsigned long len = 4;

	txbuf[0] = 0x81;
	txbuf[1] = 0x0f;
	txbuf[2] = 0x01;
	txbuf[3] = 0x02;
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	txbuf[0] = 0x81;
	txbuf[1] = 0x0d;
	txbuf[2] = 0x01;
	txbuf[3] = 0x01;
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 7;
	pReadData(0, 1, rxbuf, &len);
	txbuf[3] = 0x02;
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 8;
	pReadData(0, 1, rxbuf, &len);
	txbuf[0] = 0x81;
	txbuf[1] = 0x06;
	txbuf[2] = 0x01;
	txbuf[3] = 0x01;
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	txbuf[0] = 0x81;
	txbuf[1] = 0x02;
	txbuf[2] = 0x01;
	txbuf[3] = 0x0A;
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	txbuf[0] = 0x81;
	txbuf[1] = 0x01;
	txbuf[2] = 0x08;
	txbuf[3] = (uint8_t)(chipiaddr >> 24);
	txbuf[4] = (uint8_t)(chipiaddr >> 16);
	txbuf[5] = (uint8_t)(chipiaddr >> 8);
	txbuf[6] = (uint8_t)chipiaddr;
	txbuf[7] = (uint8_t)(length >> 24);
	txbuf[8] = (uint8_t)(length >> 16);
	txbuf[9] = (uint8_t)(length >> 8);
	txbuf[10] = (uint8_t)(length);
	len = 11;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	txbuf[0] = 0x81;
	txbuf[1] = 0x02;
	txbuf[2] = 0x01;
	txbuf[3] = 0x05;
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);

	switch (riscvchip)
	{
	case 3:
		wlink_ramcodewrite(flash_op569, sizeof(flash_op569));
		break;
	case 1:

		wlink_ramcodewrite(flash_op103, sizeof(flash_op103));
		break;
	case 2:
		wlink_ramcodewrite(flash_op573, sizeof(flash_op573));
		break;
	case 5:
	case 6:
		wlink_ramcodewrite(flash_op307, sizeof(flash_op307));
		break;
	default:;
	}
	txbuf[0] = 0x81;
	txbuf[1] = 0x02;
	txbuf[2] = 0x01;
	txbuf[3] = 0x09;
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	len = 4;
	txbuf[3] = 0x03;
	pWriteData(0, 1, txbuf, &len);
	len = 4;
	pReadData(0, 1, rxbuf, &len);
	int i = 0;
	int ret;
	switch (riscvchip)
	{
	case 3:
		ret = length % 256;
		if (ret)
		{
			for (int j = 0; j < (256 - ret); j++)
			{
				*(buffer + length + j) = 0xff;
			}
			while (length - ret + 256)
			{
				len = 64;
				pWriteData(0, 2, buffer + i, &len);
				i += 64;
				length -= 64;
				if (!(i % 4096))
				{
					len = 4;
					pReadData(0, 2, rxbuf, &len);
					if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x04)))
					{
					}
					else
					{
						LOG_ERROR("Verify failed");
						return ERROR_FAIL;
					}
				}
			}
			break;
		}
		else
		{
			while (length)
			{
				len = 64;
				pWriteData(0, 2, buffer + i, &len);
				i += 64;
				length -= 64;
				if (!(i % 4096))
				{
					len = 4;
					pReadData(0, 2, rxbuf, &len);
					if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x04)))
					{
					}
					else
					{
						LOG_ERROR("Verify failed");
						return ERROR_FAIL;
					}
				}
			}
			break;
		}
	case 1:
		ret = length % 128;
		if (ret)
		{
			for (int j = 0; j < (128 - ret); j++)
			{
				*(buffer + length + j) = 0xff;
			}
			while (length - ret + 128)
			{
				len = 64;
				pWriteData(0, 2, buffer + i, &len);
				i += 64;
				length -= 64;
				if (!(i % 4096))
				{
					len = 4;
					pReadData(0, 2, rxbuf, &len);
					if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x04)))
					{
					}
					else
					{
						LOG_ERROR("Verify failed");
						return ERROR_FAIL;
					}
				}
			}
			break;
		}
		else
		{
			while (length)
			{
				len = 64;
				pWriteData(0, 2, buffer + i, &len);
				i += 64;
				length -= 64;
				if (!(i % 4096))
				{
					len = 4;
					pReadData(0, 2, rxbuf, &len);
					if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x04)))
					{
					}
					else
					{
						LOG_ERROR("Verify failed");
						return ERROR_FAIL;
					}
				}
			}
			break;
		}
	case 2:
		ret = length % 256;
		i = 0;
		if (ret)
		{
			for (int j = 0; j < (256 - ret); j++)
			{
				*(buffer + length + j) = 0xff;
			}

			while (length - ret + 256)
			{
				len = 64;

				pWriteData(0, 2, buffer + i, &len);

				i += 64;
				length -= 64;
				if (!(i % 4096))
				{
					len = 4;
					pReadData(0, 2, rxbuf, &len);
					if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x04)))
					{
					}
					else
					{
						LOG_ERROR("Verify failed");
						return ERROR_FAIL;
					}
				}
			}

			if (i < 4096)
			{
				len = 4;
				pReadData(0, 2, rxbuf, &len);
				if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x04)))
				{
				}
				else
				{
					LOG_ERROR("Verify failed");
					return ERROR_FAIL;
				}
			}
			break;
		}
		else
		{
			while (length)
			{
				len = 64;
				pWriteData(0, 2, buffer + i, &len);
				i += 64;
				length -= 64;
				if (!(i % 4096))
				{
					len = 4;
					pReadData(0, 2, rxbuf, &len);
					if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x04)))
					{
					}
					else
					{
						LOG_ERROR("Verify failed");
						return ERROR_FAIL;
					}
				}
			}
			break;
		}
	case 5:
	case 6:
		ret = length % 256;
		if (ret)
		{
			for (int j = 0; j < (256 - ret); j++)
			{
				*(buffer + length + j) = 0xff;
			}
			while (length - ret + 256)
			{
				len = 64;
				pWriteData(0, 2, buffer + i, &len);
				i += 64;
				length -= 64;
				if (!(i % 4096))
				{
					len = 4;
					pReadData(0, 2, rxbuf, &len);
					if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x04)))
					{
					}
					else
					{
						LOG_ERROR("Verify failed");
						return ERROR_FAIL;
					}
				}
			}

			break;
		}
		else
		{
			while (length)
			{
				len = 64;
				pWriteData(0, 2, buffer + i, &len);
				i += 64;
				length -= 64;
				if (!(i % 4096))
				{
					len = 4;
					pReadData(0, 2, rxbuf, &len);
					if (((rxbuf[0] == 0x41) && (rxbuf[1] == 0x01) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x04)))
					{
					}
					else
					{
						LOG_ERROR("Verify failed");
						return ERROR_FAIL;
					}
				}
			}

			break;
		}

	default:
		break;
	}
	LOG_INFO("Verify Success");
	return ERROR_OK;
}
int wlink_erase(void)
{
	int ret;
	unsigned char txbuf[4];
	unsigned char rxbuf[4];
	unsigned long len = 4;
	txbuf[0] = 0x81;
	txbuf[1] = 0x02;
	txbuf[2] = 0x01;
	txbuf[3] = 0x01;
	ret=pWriteData(0, 1, txbuf, &len);
	len = 4;
	ret=pReadData(0, 1, rxbuf, &len);
	return ret;
}
void readmcause()
{
	unsigned char oAddr;
	unsigned long oData;
	unsigned char oOP;
	DMI_OP(0, 0x16, 0x00000700, 2, &oAddr, &oData, &oOP);
	DMI_OP(0, 0x17, 0x220342, 2, &oAddr, &oData, &oOP);
	DMI_OP(0, 0x16, 0, 1, &oAddr, &oData, &oOP);
	DMI_OP(0, 0x4, 0, 1, &oAddr, &oData, &oOP);
	DMI_OP(0, 0x17, 0x220343, 2, &oAddr, &oData, &oOP);
	DMI_OP(0, 0x16, 0, 1, &oAddr, &oData, &oOP);
	DMI_OP(0, 0x4, 0, 1, &oAddr, &oData, &oOP);
	DMI_OP(0, 0x20, 0, 1, &oAddr, &oData, &oOP);
	DMI_OP(0, 0x21, 0, 1, &oAddr, &oData, &oOP);
	DMI_OP(0, 0x22, 0, 1, &oAddr, &oData, &oOP);
}

int wlink_execute_queue(void)
{
	return ERROR_OK;
}

int wlink_init(void)
{	
	unsigned char txbuf[4];
	unsigned char rxbuf[20];
	char * wlink_name=NULL;
	uint64_t old_dpc_value, new_dpc_value, t6_new, t6_old;
	uint32_t dmcontrol;
	txbuf[0] = 0x81;
	txbuf[1] = 0x0d;
	txbuf[2] = 0x01;
	txbuf[3] = 0x01;
	unsigned long len = 4;

#ifdef _WIN32
	OSVERSIONINFO version;

	version.dwOSVersionInfoSize = sizeof version;
	if (!GetVersionEx(&version))
	{
		LOG_ERROR("GetVersionEx error");
		return ERROR_FAIL;
	}
	if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
	{
		LOG_ERROR("Not Win32 Platform");
		return ERROR_FAIL;
	}
	if (hModule == 0)
	{
		hModule = LoadLibrary("WCHLinkDll.dll");
		if (hModule)
		{
			pOpenDev = (pCH375OpenDevice)GetProcAddress(hModule, "CH375OpenDevice");
			pCloseDev = (pCH375CloseDevice)GetProcAddress(hModule, "CH375CloseDevice");
			pSetTimeout = (pCH375SetTimeout)GetProcAddress(hModule, "CH375SetTimeout");
			pReadData = (pCH375ReadEndP)GetProcAddress(hModule, "CH375ReadEndP");
			pWriteData = (pCH375WriteEndP)GetProcAddress(hModule, "CH375WriteEndP");
			if (pOpenDev == NULL || pCloseDev == NULL || pSetTimeout == NULL || pReadData == NULL || pWriteData == NULL)
			{
				LOG_ERROR("GetProcAddress error");
				return ERROR_FAIL;
			}
			if (pOpenDev(gIndex) == -1)
			{
				gOpen = FALSE;
				LOG_ERROR("WLink Open Error");
				return ERROR_FAIL;
			}
			pSetTimeout(gIndex, 5000, 5000);
		}
	}
#else if

	if (jtag_libusb_open(wlink_vids, wlink_pids, &wfd, NULL) != ERROR_OK)
	{
		LOG_ERROR("open failed");
		goto error_wlink;
	}
	jtag_libusb_set_configuration(wfd, 0);
	if (libusb_claim_interface(wfd, 0) != ERROR_OK)
	{
		LOG_ERROR("claim interface failed");
		goto error_wlink;
	}

#endif
	len = 4;
	pWriteData(0, 1, txbuf, &len);
	len = 7;
	if (pReadData(0, 1, rxbuf, &len))
	{
		switch (rxbuf[5])
		{
		case 1:
			wlink_name="WCH-Link-CH549  mod:RV";
			break;
		case 2:
			wlink_name="WCH-LinkE-CH32V307  mod:RV";
			break;
		case 3:
			wlink_name="WCH-LinkS-CH32V203  mod:RV";
			break;
		case 4:
			wlink_name="WCH-LinkB  mod:RV";
			break;
		default:
			LOG_ERROR("unknow WCH-LINK ");	
			break;
		}
		LOG_INFO("%s version %d.%d ",wlink_name, rxbuf[3], rxbuf[4]);
		txbuf[3] = 0x02;
		len = 4;
		pWriteData(0, 1, txbuf, &len);
		len = 8;
		pReadData(0, 1, rxbuf, &len);
		if (((rxbuf[0] == 0x81) && (rxbuf[1] == 0x55) && (rxbuf[2] == 0x01) && (rxbuf[3] == 0x01)))
		{
			LOG_ERROR(" WCH-Link failed to connect with riscvchip");
			LOG_ERROR(" 1.Make sure the two-line debug interface has been opened. If not, set board to boot mode then use ISP tool to open it");
			LOG_ERROR(" 2.Please check your physical link connection");
			return ERROR_FAIL;
		}
		chip_type=(((unsigned int)rxbuf[4])<<24) + (((unsigned int)rxbuf[5])<<16) + (((unsigned int)rxbuf[6])<<8) +(((unsigned int) rxbuf[7]));
		switch (rxbuf[3])
		{
		case 1:
		{
			riscvchip = 0x01;
			chipiaddr = 0x08000000;
			pagesize = 128;		
			txbuf[0] = 0x81;
			txbuf[1] = 0x06;
			txbuf[2] = 0x01;
			txbuf[3] = 0x01;
			len = 4;
			pWriteData(0, 1, txbuf, &len);
			len = 4;
			pReadData(0, 1, rxbuf, &len);
			if(rxbuf[2]==rxbuf[3]==1){
				LOG_ERROR("Read-Protect Status Currently Enabled");
				 return ERROR_FAIL;	
			}
			txbuf[0] = 0x81;
			txbuf[1] = 0x0d;
			txbuf[2] = 0x01;
			txbuf[3] = 0x03;
			len = 4;
			pWriteData(0, 1, txbuf, &len);
			len = 4;
			if(pReadData(0, 1, rxbuf, &len)){
					uint64_t old_dpc_value, new_dpc_value, t6_new, t6_old;
					uint32_t dmcontrol;
					uint32_t addr = 4;
					unsigned char oAddr;
					unsigned long oData;
					unsigned char oOP;
					unsigned char iAddr;
					unsigned char Txbuf[52] = {0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
											   0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
											   0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,
											   0x73, 0x00, 0x10, 0x00};				
					DMI_OP(0, 0x20, 0x0002a283, 2, &oAddr, &oData, &oOP);
					DMI_OP(0, 0x21, 0x00100073, 2, &oAddr, &oData, &oOP);
					DMI_OP(0, 0x04, 0, 2, &oAddr, &oData, &oOP);
					DMI_OP(0, 0x17, 0x00271005, 2, &oAddr, &oData, &oOP);
					DMI_OP(0, 0x17, 0x00221005, 2, &oAddr, &oData, &oOP);
					DMI_OP(0, 0x04, iAddr, 1, &oAddr, &oData, &oOP);
					WriteNonFullPage(addr, Txbuf, sizeof(Txbuf));					
					int ret = DMI_OP(0, 0x04, 0x00000020, 2, &oAddr, &oData, &oOP);
					usleep(1000);
					DMI_OP(0, 0x17, 0x0023101F, 2, &oAddr, &oData, &oOP);
					usleep(1000);
					DMI_OP(0, 0x16, iAddr, 1, &oAddr, &oData, &oOP);
					usleep(1000);
					DMI_OP(0, 0x20, 0x000f8067, 2, &oAddr, &oData, &oOP);
					usleep(1000);
					DMI_OP(0, 0x21, 0x00100073, 2, &oAddr, &oData, &oOP);
					usleep(1000);
					DMI_OP(0, 0x17, 0x00241000, 2, &oAddr, &oData, &oOP);
					usleep(1000);
					DMI_OP(0, 0x16, iAddr, 1, &oAddr, &oData, &oOP);
					usleep(1000);
					wlink_reset();
				}
			break;
		}
		case 2:
		{
			riscvchip = 0x02;
			chipiaddr = 0x00000000;
			pagesize = 256;
			LOG_WARNING(" The debug interface has been opened,there is a risk of code leakage ,ensure that the debug interface has been closed before leaving factory !");
			break;
		}
		case 3:
		{
			riscvchip = 0x03;
			chipiaddr = 0x0000;
			pagesize = 256;
			LOG_WARNING(" The debug interface has been opened,there is a risk of code leakage ,ensure that the debug interface has been closed before leaving factory !");
			txbuf[0] = 0x81;
			txbuf[1] = 0x0d;
			txbuf[2] = 0x01;
			txbuf[3] = 0x04;
		
			len=4;
			pWriteData(0, 1, txbuf, &len);
			len = 4;
			pReadData(0, 1, rxbuf, &len);

			switch (rxbuf[3])
			{
			case 0:
			{
				ramaddr = 0x8000;
				break;
			}
			case 1:
			{
				ramaddr = 0x10000;
				break;
			}
			case 3:
			{
				ramaddr = 0x18000;
				break;
			}
			default:
				LOG_ERROR(" unknow CH56X riscvchip");
				return ERROR_FAIL;
			}

			break;
		}
		case 5:{			
			riscvchip = 0x05;
			chipiaddr = 0x08000000;
			pagesize = 256;
			txbuf[3] = 0x03;
			len = 4;
			pWriteData(0, 1, txbuf, &len);
			len = 4;
			pReadData(0, 1, rxbuf, &len);
			txbuf[0] = 0x81;
			txbuf[1] = 0x06;
			txbuf[2] = 0x01;
			txbuf[3] = 0x01;
			len = 4;
			pWriteData(0, 1, txbuf, &len);
			len = 4;
			pReadData(0, 1, rxbuf, &len);
			if(rxbuf[2]==rxbuf[3]==1){
				LOG_ERROR("Read-Protect Status Currently Enabled");
				 return ERROR_FAIL;	
				}
			break;
		}
		case 6:
		{
			riscvchip = 0x06;
			chipiaddr = 0x08000000;
			pagesize = 256;
			txbuf[3] = 0x03;
			len = 4;
			pWriteData(0, 1, txbuf, &len);
			len = 4;
			pReadData(0, 1, rxbuf, &len);
			txbuf[0] = 0x81;
			txbuf[1] = 0x06;
			txbuf[2] = 0x01;
			txbuf[3] = 0x01;
			len = 4;
			pWriteData(0, 1, txbuf, &len);
			len = 4;
			pReadData(0, 1, rxbuf, &len);
			if(rxbuf[2]==rxbuf[3]==1){
				LOG_ERROR("Read-Protect Status Currently Enabled");
				 return ERROR_FAIL;	
			}
			break;
		}
		case 7: // 
		{
			riscvchip = 0x02;
			chipiaddr = 0x00000000;
			pagesize = 256;
			LOG_WARNING(" The debug interface has been opened,there is a risk of code leakage ,ensure that the debug interface has been closed before leaving factory !");
			break;
		}
		default:
			LOG_ERROR(" communication fail,please contact [support@mounriver.com]");
			return ERROR_FAIL;
		}
#ifdef _WIN32
		gOpen = TRUE;
#endif
	}
	else
	{
		return ERROR_FAIL;
	}
	LOG_INFO("wlink_init ok");
	return ERROR_OK;
#ifdef _WIN32

#else
error_wlink:
	if(wfd)
		jtag_libusb_close(wfd);
	return ERROR_FAIL;
#endif
}

int wlink_quit(void)
{
#ifdef _WIN32
	if (gOpen)
	{
		pCloseDev(gIndex);
		gOpen = FALSE;
	}
	if (hModule)
	{
		FreeLibrary(hModule);
		hModule = 0;
	}
#else if
	jtag_libusb_close(wfd);
#endif
	return ERROR_OK;
}

void wlink_disabledebug(void)
{
	if ((riscvchip == 0x02) || (riscvchip == 0x03))
	{
		unsigned char txbuf[4];
		unsigned char rxbuf[4];
		unsigned long len = 4;
		txbuf[0] = 0x81;
		txbuf[1] = 0x0e;
		txbuf[2] = 0x01;
		txbuf[3] = 0x01;
		len = 4;
		pWriteData(0, 1, txbuf, &len);
		len = 4;
		pReadData(0, 1, rxbuf, &len);
	}
	
}
int wlink_write(const uint8_t *buffer, uint32_t offset, uint32_t count)
{

	uint8_t buf_bin[4 * 1024];
	int binlength = count;
	wlink_ready_write(offset,count);
	memset(buf_bin,0xff,4 * 1024);
	if (binlength <= 4096)
	{
		for (int i = 0; i < count; i++)
		{
			buf_bin[i] = *(buffer + i);
		}
		int ret = wlink_fastprogram(buf_bin);
		if (ret != ERROR_OK)
		{
			return ERROR_FAIL;
		}
	}
	else
	{
		while (binlength >= 4096)
		{
			for (int i = 0; i < 4096; i++)
			{
				buf_bin[i] = *(buffer + i);
			}
			int ret = wlink_fastprogram(buf_bin);
			if (ret != ERROR_OK)
			{
				return ERROR_FAIL;
			}
			binlength -= 4096;
			buffer += 4096;
		}
		if (binlength > 0)
		{
			for (int i = 0; i < binlength; i++)
			{
				buf_bin[i] = *(buffer + i);
			}
			int ret = wlink_fastprogram(buf_bin);
			if (ret != ERROR_OK)
			{
				return ERROR_FAIL;
			}
		}
	}
	wlink_endprogram();
	return ERROR_OK;
}


/*ARM*/













COMMAND_HANDLER(wlink_set_index)
{
	if (CMD_ARGC == 1)
		COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], gIndex);
	return ERROR_OK;
}

COMMAND_HANDLER(wlink_set)
{
	wchwlink=true;
	return ERROR_OK;
}
COMMAND_HANDLER(noload)
{
	noloadflag=1;
	return ERROR_OK;
}
COMMAND_HANDLER(page_erase)
{
	pageerase=true;
	return ERROR_OK;
}
static const struct command_registration wlink_command_handlers[] = {
	{
		.name = "wlink_set_index",
		.handler = &wlink_set_index,
		.mode = COMMAND_CONFIG,
		.help = "wlink_set_index num",
		.usage = "set Wlink index",
	},
	{
		.name = "wlink_set",
		.handler = &wlink_set,
		.mode = COMMAND_CONFIG,
		.help = "wlink_set",
		.usage = "",
	},
	{
		.name = "noload",
		.handler = &noload,
		.mode = COMMAND_CONFIG,
		.help = "noload",
		.usage = "dont download",
	},
	{
		.name = "page_erase",
		.handler = &page_erase,
		.mode = COMMAND_CONFIG,
		.help = "page_erase",
		.usage = "page erase",
	},
	COMMAND_REGISTRATION_DONE
};
static struct jtag_interface wlink_interface = {
	
	.supported = DEBUG_CAP_TMS_SEQ,
	.execute_queue = wlink_execute_queue,
};
struct adapter_driver wlink_adapter_driver = {
	.name = "wlink",

	.commands = wlink_command_handlers,
	.transports = jtag_only,

	.init = wlink_init,
	.quit = wlink_quit,
	.jtag_ops = &wlink_interface,
};
